import { isSameVnode } from "./index";

//createElm生成真实结点
export function createElm(vnode) {
  let { tag, data, children, text } = vnode;
  if (typeof tag === 'string') {
    vnode.el = document.createElement(tag);
    patchProps(vnode.el, {}, data);
    children.forEach(child => {
      vnode.el.appendChild(createElm(child));
    });
  } else {
    vnode.el = document.createTextNode(text)
  }
  return vnode.el;
}
export function patchProps(el, oldProps = {}, props = {}) {
  //比较属性,老的属性有新的没有,要删除老的
  let oldStyles = oldProps.style;
  let newStyles = props.style;
  for (let key in oldStyles) {
    if (!newStyles[key]) {
      el.style[key] = '';
    }
  }
  for (let key in oldStyles) {
    if (!props[key]) {
      el.removeAttribute[key] = '';
    }
  }


  for (let key in props) {
    if (key === 'style') {
      for (let styleName in props.style) {
        el.style[styleName] = props.style[styleName];
      }
    } else {
      el.setAttribute(key, props[key]);
    }
  }


}
// patch作用是根据虚拟DOM生成真实的DOM,并挂载在页面
export function patch(oldNode, vnode) {
  //初次渲染
  const isRealElement = oldNode.nodeType;
  if (isRealElement) {
    const elm = oldNode;
    const parentElm = elm.parentNode;
    let newElm = createElm(vnode); //newElm是模板引擎处理后得到得真实DOM
    parentElm.insertBefore(newElm, elm.nextSibling);
    parentElm.removeChild(elm); //删除原有得DO元素
    return newElm;
  } else { //跟新DOM结点
    // diff算法
    return patchVnode(oldNode, vnode);

  }
}

function patchVnode(oldNode, vnode) {
  //比较tag 和 key 是否相同不同直接替换
  if (!isSameVnode(oldNode, vnode)) {
    return oldNode.el.parentNode.replaceChild(createElm(vnode), oldNode.el)
  }
  //标签相同,比较文本
  let el = vnode.el = oldNode.el;
  if (oldNode.text !== vnode.text) {
    el.textContent = vnode.text;
  }
  //是标签 比较属性
  patchProps(el, oldNode.data, vnode.data);

  //比较儿子结点
  /**
   * 情况: 
   *      1.双方都有儿子
   *      2.一方有
   *      3.都没有
   */
  let oldChildren = oldNode.children || [];
  let newChildren = vnode.children || [];
  if (oldChildren.length > 0 && newChildren.length > 0) {
    updateChildren(el, oldChildren, newChildren);
  } else if (oldChildren.length > 0) {
    el.innerHTML = '';
  } else if (newChildren.length > 0) {
    moumtChildren(el, newChildren);
  }
  return el;
}

function moumtChildren(el, newChildren) {
  for (let i = 0; i < newChildren.length; i++) {
    let child = newChildren[i];
    el.appendChild(createElm(child));
  }

}
function updateChildren(el, oldChildren, newChildren) {
  // 我们操作列表 经常会是有 push shift pop unshift reverse sort这些方法(针对这些情况
  // vue2中采用双指针的方式 比较两个节点 
  let oldStartIndex = 0;
  let newStartIndex = 0;
  let oldEndIndex = oldChildren.length - 1;
  let newEndIndex = newChildren.length - 1;
  let oldStartVnode = oldChildren[0];
  let newStartVnode = newChildren[0]
  let oldEndVnode = oldChildren[oldEndIndex];
  let newEndVnode = newChildren[newEndIndex];
  // 乱序排序 旧的表的映射表函数
  function makeIndexByKey(children) {
    let map = {

    }
    children.forEach((child, index) => {
      map[child.key] = index;
    })
    return map;
  }
  let map = makeIndexByKey(oldChildren); //map映射表对象

  while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) {
    // 停止循环条件
    if (!oldStartVnode) {
      oldStartVnode = oldChildren[++oldstartIndex];
    } else if (!oldEndVnode) {
      oldEndVnode = oldChildren[--oldEndIndex];
    } else if (isSameVnode(oldStartVnode, newStartVnode)) {// 双方有一方头指针，大于尾部指针则停止循环
      patchVnode(oldStartVnode, newStartVnode);// 如果是相同节点 则递归比较子节点 
      oldStartVnode = oldChildren[++oldStartIndex];
      newStartVnode = newChildren[++newStartIndex]// 比较开头节点
    } else if (isSameVnode(oldEndVnode, newEndVnode)) {
      patchVnode(oldEndVnode, newEndVnode);// 如果是相同节点 则递归比较子节点
      oldEndVnode = oldChildren[--oldEndIndex];
      newEndVnode = newChildren[--newEndIndex];// 比较开头节点
    } else if (isSameVnode(oldEndVnode, newStartVnode)) {
      patchVnode(oldEndVnode, newStartVnode);
      // insertBefore 具备移动性 会将原来的元素移动走
      el.insertBefore(oldEndVnode.el.oldStartVnode.el)//将老的尾巴移动到老的前面去 
      oldEndVnode = oldChildren[--oldEndIndex];
      newStartVnode = newChildren[++newStartIndex];
    } else if (isSameVnode(oldStartVnode, newEndVnode)) {
      patchVnode(oldStartVnode, newEndVnode);
      // insertBefore 具备移动性 会将原来的元素移动走
      el.insertBefore(oldStartVnode.el, oldEndVnode.el.nextSibling);// 将老的尾巴移动到老的前面去
      oldStartVnode = oldChildren[++oldstartIndex];
      newEndVnode = newChildren[--newEndIndex];
    } else {
      // 乱序比较
      let moveIndex = map[newStartVnode.key];
      if (moveIndex !== undefined) {
        let moveVnode = oldChildren[moveIndex];
        el.insertBefore(moveVnode.el, oldStartVnode.el);
        oldChildren[moveIndex] = undefined;
        patchVnode(moveVnode, newStartVnode);
      } else {
        el.insertBefore(createElm(newStartVnode, oldStartVnode.el))
      }
    }

  }
  if (newStartIndex <= newEndIndex) { // 新的多了 多余的就插入进去
    for (let i = newStartIndex; i <= newEndIndex; i++) {
      let childEl = createElm(newChildren[i])
      // 这里可能是像后追加 ，还有可能是向前追加 
      let ancher = newChildren[newEndIndex + 1] ? newChildren[newEndIndex + 1].el : null;
      el.appendchild(childEl, ancher);
    }
    if (oldStartIndex <= oldEndIndex) {// 老的对了，需要删除老的
      for (let i = oldStartIndex; i <= oldEndIndex; i++) {
        if (oldstartIndex[i]) {
          let childEl = oldChildren[i].el
          el.removeChild(childEl);
        }
      }
    }
  }
}
